//! Swagger/OpenAPI 文档生成模块

use crate::routers::RouteInfo;
use serde::{Deserialize, Serialize};

/// Swagger配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SwaggerConfig {
    pub title: String,
    pub version: String,
    pub description: Option<String>,
    pub host: Option<String>,
    pub base_path: Option<String>,
    pub schemes: Vec<String>,
}

impl Default for SwaggerConfig {
    fn default() -> Self {
        Self {
            title: "API Documentation".to_string(),
            version: "1.0.0".to_string(),
            description: None,
            host: None,
            base_path: Some("/api".to_string()),
            schemes: vec!["http".to_string(), "https".to_string()],
        }
    }
}

impl SwaggerConfig {
    pub fn new(title: &str, version: &str) -> Self {
        Self {
            title: title.to_string(),
            version: version.to_string(),
            ..Default::default()
        }
    }

    pub fn with_description(mut self, description: &str) -> Self {
        self.description = Some(description.to_string());
        self
    }

    pub fn with_host(mut self, host: &str) -> Self {
        self.host = Some(host.to_string());
        self
    }

    pub fn with_base_path(mut self, base_path: &str) -> Self {
        self.base_path = Some(base_path.to_string());
        self
    }
}

/// Swagger文档生成器
pub struct SwaggerGenerator {
    config: SwaggerConfig,
    routes: Vec<RouteInfo>,
}

impl SwaggerGenerator {
    pub fn new(config: SwaggerConfig) -> Self {
        Self {
            config,
            routes: Vec::new(),
        }
    }

    pub fn add_route(mut self, route: RouteInfo) -> Self {
        self.routes.push(route);
        self
    }

    pub fn add_routes(mut self, routes: Vec<RouteInfo>) -> Self {
        self.routes.extend(routes);
        self
    }

    pub fn generate(&self) -> Result<serde_json::Value, String> {
        let mut paths = serde_json::Map::new();
        
        for route in &self.routes {
            let path_item = self.generate_path_item(route)?;
            paths.insert(route.path.clone(), serde_json::Value::Object(path_item));
        }

        let swagger_doc = serde_json::json!({
            "swagger": "2.0",
            "info": {
                "title": self.config.title,
                "version": self.config.version,
                "description": self.config.description
            },
            "host": self.config.host,
            "basePath": self.config.base_path,
            "schemes": self.config.schemes,
            "consumes": ["application/json"],
            "produces": ["application/json"],
            "paths": paths,
            "securityDefinitions": {
                "jwt_auth": {
                    "type": "apiKey",
                    "name": "Authorization",
                    "in": "header",
                    "description": "JWT token in format: Bearer {token}"
                }
            },
            "security": [
                {
                    "jwt_auth": []
                }
            ]
        });

        Ok(swagger_doc)
    }

    fn generate_path_item(&self, route: &RouteInfo) -> Result<serde_json::Map<String, serde_json::Value>, String> {
        let mut path_item = serde_json::Map::new();
        
        let operation = self.generate_operation(route)?;
        let method = route.method.to_lowercase();
        path_item.insert(method, serde_json::Value::Object(operation));
        
        Ok(path_item)
    }

    fn generate_operation(&self, route: &RouteInfo) -> Result<serde_json::Map<String, serde_json::Value>, String> {
        let mut operation = serde_json::Map::new();
        
        operation.insert("operationId".to_string(), 
                        serde_json::Value::String(route.handler_name.clone()));
        
        if let Some(description) = &route.description {
            operation.insert("summary".to_string(), 
                            serde_json::Value::String(description.clone()));
        }
        
        operation.insert("tags".to_string(), 
                        serde_json::Value::Array(
                            route.tags.iter()
                                .map(|tag| serde_json::Value::String(tag.clone()))
                                .collect()
                        ));
        
        operation.insert("responses".to_string(), self.generate_responses());
        
        // 添加安全要求
        if route.auth_policy.as_ref().map_or(false, |p| !p.is_empty()) {
            operation.insert("security".to_string(), serde_json::json!([{
                "jwt_auth": []
            }]));
        }
        
        Ok(operation)
    }

    fn generate_responses(&self) -> serde_json::Value {
        serde_json::json!({
            "200": {
                "description": "Success",
                "schema": {
                    "type": "object"
                }
            },
            "401": {
                "description": "Unauthorized",
                "schema": {
                    "$ref": "#/definitions/Error"
                }
            },
            "403": {
                "description": "Forbidden",
                "schema": {
                    "$ref": "#/definitions/Error"
                }
            },
            "500": {
                "description": "Internal Server Error",
                "schema": {
                    "$ref": "#/definitions/Error"
                }
            }
        })
    }

    pub fn generate_yaml(&self) -> Result<String, String> {
        let json = self.generate()?;
        serde_yaml::to_string(&json).map_err(|e| e.to_string())
    }

    pub fn save_to_file(&self, path: &str) -> Result<(), String> {
        let json = self.generate()?;
        std::fs::write(path, serde_json::to_string_pretty(&json).map_err(|e| e.to_string())?)
            .map_err(|e| e.to_string())?;
        Ok(())
    }
}

/// 用于utoipa的OpenAPI生成器
#[cfg(feature = "utoipa")]
pub struct OpenApiGenerator {
    #[allow(dead_code)]
    config: SwaggerConfig,
}

#[cfg(feature = "utoipa")]
impl OpenApiGenerator {
    pub fn new(config: SwaggerConfig) -> Self {
        Self { config }
    }

    pub fn generate_openapi(&self) -> utoipa::openapi::OpenApi {
        use utoipa::openapi::OpenApiBuilder;
        
        OpenApiBuilder::new()
            .info(
                utoipa::openapi::InfoBuilder::new()
                    .title(&self.config.title)
                    .version(&self.config.version)
                    .description(Some(&self.config.description.clone().unwrap_or_default()))
                    .build()
            )
            .paths(utoipa::openapi::Paths::new())
            .components(Some(
                utoipa::openapi::ComponentsBuilder::new()
                    .security_scheme(
                        "jwt_auth",
                        utoipa::openapi::security::SecurityScheme::Http(
                            utoipa::openapi::security::HttpBuilder::new()
                                .scheme(utoipa::openapi::security::HttpAuthScheme::Bearer)
                                .bearer_format("JWT")
                                .description(Some("JWT token in format: Bearer {token}".to_string()))
                                .build()
                        )
                    )
                    .build()
            ))
            .build()
    }
}